#include <memory>
#include <mutex>
#include <stack>

struct empty_stack : std::exception
{
	const char* what() const throw() ;
};

template<typename T>
class threadsafe_stack
{
private:
	std::stack<T> _data;
	mutable std::mutex _m;
public:
	threadsafe_stack(){}
	threadsafe_stack(const threadsafe_stack& other);
	threadsafe_stack& operator=(const threadsafe_stack&);
	void push(T new_value);
	std::shared_ptr<T> pop();
	void pop(T& value);
	bool empty() const;
};

template<typename T>
threadsafe_stack<T>::threadsafe_stack(const threadsafe_stack& other)
{
	std::lock_guard<std::mutex> lock(other._m);
	_data = other._data;
}
template<typename T>
void threadsafe_stack<T>::push(T new_value)
{
	std::lock_guard<std::mutex> lock(_m);
	_data.push(new_value);
}
template<typename T>
std::shared_ptr<T> threadsafe_stack<T>::pop()
{
	std::lock_guard<std::mutex> lock(_m);
	if(_data.empty()) throw empty_stack();
	std::shared_ptr<T> const res(std::make_shared<T>(_data.top()));
	_data.pop();
	return res;
}
template<typename T>
void threadsafe_stack<T>::pop(T& value)
{
	std::lock_guard<std::mutex> lock(_m);
	if(_data.empty()) throw empty_stack();
	value = _data.top();
	_data.pop();
}
template<typename T>
bool threadsafe_stack<T>::empty() const
{
	std::lock_guard<std::mutex> lock(_m);
	return _data.empty();
}
